package com.epam.bank;

import java.util.Properties;
import java.util.Random;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.log4j.Logger;

import com.epam.properties_loader.PropertiesHelper;

public class Bank {
	private static LinkedBlockingQueue<Cashier> cashiers;
	private static LinkedBlockingQueue<Spectator> spectators;
	private static Bank instance=null;
	private static float eurUsdRate;
	private static Logger logger=Logger.getLogger(Bank.class);
	private static  Properties props = new PropertiesHelper().getProperties();
	private static Random rand=new Random();
	
	private Bank() {
		int numOfCashiers=Integer.valueOf(props.getProperty("NumberOfCashiers"));
		int numOfSpectators=Integer.valueOf(props.getProperty("NumberOfSpectators"));
		cashiers=new LinkedBlockingQueue<Cashier>(numOfCashiers);
		spectators=new LinkedBlockingQueue<Spectator>(numOfSpectators);
		eurUsdRate=Float.valueOf(props.getProperty("EurUsdRate"));
		for (int i=0; i<numOfCashiers; i++) {
			cashiers.add(new Cashier(rand.nextInt(300), rand
					.nextInt(300)));
		}
		for (int i=0; i<numOfSpectators; i++) {
			spectators.add(new Spectator());
		}
	}
	
	public static synchronized Bank getInstance() {
		if (instance==null) {
			instance=new Bank();
		}
		return instance;
	}
	
	public Cashier getCashier() {
		Cashier res=null;
		try {
			res=cashiers.take();
			logger.debug("Cashier "+res.getId()+" taken! "+cashiers.size()+
					"/4 cashiers available");
			if (!res.isEnoughCash()) {
				Spectator spectator = spectators.take();
				logger.debug("Spectator taken! "+spectators.size()+"/2 spectators available");
				spectator.bringCash(res);
				spectators.offer(spectator);
				logger.debug("Spectator released! "+spectators.size()+
						"/2 spectators available");
			}
		} catch (InterruptedException e) {
			logger.error("Couldn't take a cashier!");
		}
		return res;
	}
	
	public static void releaseCashier(Cashier cashier) {
		cashiers.offer(cashier);
		logger.debug("Cashier "+cashier.getId()+" released! "+
				cashiers.size()+" cashiers available!");
	}
	
	public synchronized Action randomAction() {
		switch (rand.nextInt(5)) {
		case 0:
			return Action.WITHDRAW;
		case 1:
			return Action.DEPOSIT;
		case 2:
			return Action.TRANSFER;
		case 3:
			return Action.PAY;
		case 4: 
			return Action.EXCHANGE;
		}
		return null;
	}

	public static synchronized float getEurUsdRate() {
		return eurUsdRate;
	}
}
